package com.cskt.petproject178.service.impl;

import com.cskt.petproject178.config.OrderDelayQueueConfig;
import com.cskt.petproject178.mapper.OrderItemMapper;
import com.cskt.petproject178.mapper.OrderMapper;
import com.cskt.petproject178.mapper.SkuMapper;
import com.cskt.petproject178.mapper.SpuMapper;
import com.cskt.petproject178.pojo.entity.Order;
import com.cskt.petproject178.pojo.entity.OrderItem;
import com.cskt.petproject178.pojo.exception.BaseException;
import com.cskt.petproject178.pojo.param.AddOrderParam;
import com.cskt.petproject178.pojo.vo.*;
import com.cskt.petproject178.service.OrderService;
import com.cskt.petproject178.service.third.AliyunOSSService;
import com.cskt.petproject178.util.Constant;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 27013
 **/

@Service
public class OrderServiceImpl implements OrderService {
    private static final Logger log = LoggerFactory.getLogger(OrderServiceImpl.class);
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private SpuMapper spuMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private SkuMapper skuMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private AliyunOSSService aliyunOSSService;
    @Resource
    private AmqpTemplate amqpTemplate; //发送消息的客户端
    @Autowired
    private OrderDelayQueueConfig orderDelayQueueConfig;

    @Override
    public PreSubmitVO selectPreSubmitCondition(List<Map<String, Object>> condition) {
        List<PreSubmitProductVO> preSubmitProductVOList=new ArrayList<>();
        BigDecimal totalMoney=BigDecimal.ZERO;//总金额
        for (Map<String, Object> map : condition) {
            Long skuId = Long.valueOf(map.get("skuId").toString());
            Integer skuNum = (Integer) map.get("skuNum");
            PreSubmitSkuDto preSubmitSkuDto = skuMapper.selectPreSubmitProductVOBySkuId(skuId);
            //调用校验商品是否存在，是否下架，是否库存不足的方法
            preSubmitSkuDto(preSubmitSkuDto, skuId, skuNum);
            //将preSubmitSkuDto转为PreSubmitProductVO
            PreSubmitProductVO preSubmitProductVO = new PreSubmitProductVO();
            preSubmitProductVO.setId(preSubmitSkuDto.getId());
            preSubmitProductVO.setPicUrl(aliyunOSSService.getObjUrl(preSubmitSkuDto.getPicUrl()));
            preSubmitProductVO.setTitle(preSubmitSkuDto.getTitle());
            preSubmitProductVO.setUnitPrice(preSubmitSkuDto.getPrice());
            preSubmitProductVO.setNum(skuNum);
            //将商品明细添加到集合中
            preSubmitProductVOList.add(preSubmitProductVO);
            //每一件商品的总金额
            BigDecimal singleProductMoney=preSubmitProductVO.getUnitPrice().multiply(BigDecimal.valueOf(skuNum));
            //将预提交的所有的商品总金额加在一起
            totalMoney=totalMoney.add(singleProductMoney);
        }
        //开始汇总数据
        //运费
        BigDecimal freight=BigDecimal.TEN;
        //计算支付金额=商品总金额+运费
        BigDecimal payMoney=totalMoney.add(freight);
        PreSubmitVO preSubmitVO=new PreSubmitVO();
        preSubmitVO.setFreight(freight);
        preSubmitVO.setTotalMoney(totalMoney);
        preSubmitVO.setPayMoney(payMoney);
        preSubmitVO.setProductList(preSubmitProductVOList);
        return preSubmitVO;
    }

    private static void preSubmitSkuDto(PreSubmitSkuDto preSubmitSkuDto, Long skuId, Integer skuNum) {
        //验证商品是否存在，是否下架，是否库存不足
        if (ObjectUtils.isEmpty(preSubmitSkuDto)) {
            log.warn("查询的商品不存在,skuId:{}", skuId);
            throw new BaseException(StatusEnum.PRODUCT_SPU_EMPTY);
        }
        if (preSubmitSkuDto.getValid()==0) {
            log.warn("查询的商品已下架,skuId:{}", skuId);
            throw new BaseException(StatusEnum.PRODUCT_STATUS_OFF);
        }
        if (preSubmitSkuDto.getStock()< skuNum) {
            log.warn("查询的商品库存不足,skuId:{},库存数量:{}", skuId, preSubmitSkuDto.getStock());
            throw new BaseException(StatusEnum.ADD_CART_LOW_STOCK_ERROR);
        }

    }


    private static void skuDto(SkuDto skuDto,Long skuId, Integer skuNum) {
        //验证商品是否存在，是否下架，是否库存不足
        if (ObjectUtils.isEmpty(skuDto)) {
            log.warn("查询的商品不存在,skuId:{}", skuId);
            throw new BaseException(StatusEnum.PRODUCT_SPU_EMPTY);
        }
        if (skuDto.getValid()==0) {
            log.warn("查询的商品已下架,skuId:{}", skuId);
            throw new BaseException(StatusEnum.PRODUCT_STATUS_OFF);
        }
        if (skuDto.getStock()< skuNum) {
            log.warn("查询的商品库存不足,skuId:{},库存数量:{}", skuId, skuDto.getStock());
            throw new BaseException(StatusEnum.ADD_CART_LOW_STOCK_ERROR);
        }
    }

    @Override
    @Transactional //声明式事务 -- 异常会回滚数据
    public String addOrder(Long userId, AddOrderParam param) {
        try {
            //1、订单表order表中插入一条记录
            //从现有数据类型转换成为目标类型
            Order order=new Order();
            order.setUserId(userId);
            order.setReceiverName(param.getReceiverName());
            order.setReceiverPhone(param.getReceiverPhone());
            order.setReceiverAddress(param.getReceiverAddress());
            order.setCreatedTime(LocalDateTime.now());
            //过期时间
            order.setExpirationTime(LocalDateTime.now().plusMinutes(30));
            order.setOrderStatus(Constant.OrderStatus.PENDING_PAYMENT);
            order.setPayStatus(Constant.PayStatus.UNPAID);
            //数量合计
            order.setTotalNum(param.getSkuInfos().size());
            //添加订单编号一般情况下用当前时间格式yyyyMMddHHmmssSSS
         String  orderNo = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
            order.setOrderNo(orderNo);
            //支付方式，默认线上支付
            order.setPayType(Constant.PayType.ONLINE_PAY);
            BigDecimal totalMoney=BigDecimal.ZERO;
            //将订单插入数据库
            orderMapper.insertSelective(order);
            //计算订单总金额合计
            for (Map<String, Object> skuInfo : param.getSkuInfos()) {
                Long skuId = Long.valueOf(skuInfo.get("skuId").toString());
                Integer skuNum = (Integer) skuInfo.get("skuNum");
                SkuDto skuDto = skuMapper.selectSkuDtoBySkuId(skuId);
                //校验商品是否存在，是否下架，是否库存不足
                skuDto(skuDto,skuId, skuNum);
                //计算单个订单总金额
              BigDecimal singlePreMoney=  skuDto.getPrice().multiply(BigDecimal.valueOf(skuNum));
              //汇总所有商品的总金额
              totalMoney= totalMoney.add(singlePreMoney);
                //2、sku商品规格表中调整销量同时扣减库存
                skuMapper.updateSkuBySkuIdAndSkuNum(skuId,skuNum);
                //3、订单明细表order_item新增相应的记录
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderId(order.getId());
                orderItem.setSpuId(skuDto.getSpuId());
                orderItem.setCreatedTime(LocalDateTime.now());
                orderItem.setProductName(skuDto.getTitle());
                orderItem.setProductAttr(skuDto.getProductSkuSpecification());
                orderItem.setProductPrice(skuDto.getPrice());
                orderItem.setProductQuantity(skuNum);
                orderItem.setSkuId(skuId);
                orderItem.setProductPic(aliyunOSSService.getObjUrl(skuDto.getPicUrl()));
                orderItemMapper.insertSelective(orderItem);
                //4、清空购物车--非关系型数据库，回滚需要特殊处理
                stringRedisTemplate.opsForHash().delete("pet:cart:"+userId,skuId.toString());
            }
            order.setTotalMoney(totalMoney);
            //应付金额=商品总金额+运费（包邮）
            order.setPayMoney(totalMoney);
            orderMapper.updateByPrimaryKeySelective(order);
            //将生成的订单号发送到正常的订单队列
            sendOrderNoToQueue(orderNo);
            return orderNo;
        } catch (Exception e) {
            log.error("新增订单时出现异常",e);
            //todo 需要手动处理购物车
            //手动回滚购物车数据
            for (Map<String, Object> skuInfo : param.getSkuInfos()) {
                Long skuId = Long.valueOf(skuInfo.get("skuId").toString());
                Integer skuNum = (Integer) skuInfo.get("skuNum");
                ShoppingCartVO shopping = spuMapper.getSpuProductBySkuId(skuId);
                if (ObjectUtils.isEmpty(shopping)) {
                    log.warn("查询购物车商品失败{}", skuId);
                  throw  new BaseException(StatusEnum.PRODUCT_SPU_EMPTY);
                }
                shopping.setNum(skuNum);
                shopping.setAddTime(LocalDateTime.now());
                shopping.setPrice(shopping.getUnitPrice().multiply(BigDecimal.valueOf(skuNum)));
                shopping.setPicUrl(aliyunOSSService.getObjUrl(shopping.getPicUrl()));
                //拿到用户编号进行set存入
                shopping.setUserId(userId);
                try {
                    stringRedisTemplate.opsForHash().put("pet:cart:"+userId, String.valueOf(skuId), objectMapper.writeValueAsString(shopping));
                } catch (JsonProcessingException ex) {
                   log.error("序列化商品信息出行异常",ex);
                   throw new BaseException(StatusEnum.COMMON_EXCEPTION);
                }
            }
            throw new BaseException(StatusEnum.COMMON_EXCEPTION);
        }
    }

    /**
     * 将单编号发送到消息队列
     * @param orderNo
     */
    private void sendOrderNoToQueue(String orderNo) {
        amqpTemplate.convertAndSend(OrderDelayQueueConfig.ORDER_EXCHANGE_NAME, OrderDelayQueueConfig.ORDER_ROUTING_KEY, orderNo, message -> {
            message.getMessageProperties()
                    //指定消息的过期时间,要求string类型的毫秒
                    .setExpiration("30000");
            return message;
        });
        log.info("订单编号{}发送到延迟队列成功",orderNo);
    }

    @Override
    public Order selectOrderByOrderNo(String orderNo) {
        return orderMapper.selectOrderByOrderNo(orderNo);
    }

    @Override
    public PageVO<Order> selectOrderParam(Long userId, String orderNo, Integer payStatus, Integer startingNo, Integer pageSize) {
        List<Order> ordersList = orderMapper.selectOrderParam(userId, orderNo, payStatus, startingNo, pageSize);
        Integer orderCount = orderMapper.selectOrderCount(userId, orderNo, payStatus, startingNo, pageSize);
        return PageVO.page(startingNo,pageSize,orderCount,ordersList);
    }
}
